【第1687期】「数据模型」是如何助力前端开发的
前言
文末有送书,不知道有你喜欢的吗?今日早读文章由微店@skinner投稿分享。
@skinner,微店高级前端开发工程师,主要从事微店移动端H5以及小程序开发工作,喜欢分享与写作
正文从这开始~~
一、定义
数据模型是数据特征的抽象,用来抽象定义一个业务对象。假如现在有一个用户模型,如果要抽象的描述这个用户对象,可以按照如下来定义:
const UserModel = {
name:{
type:String,
property:'name',
value:'zhangshang'
},
age:{
type:Number,
property:'age',
value:26
}}
其中,type声明数据的类型,property指明映射路径,value是默认值。这里先有个大概的概念就行,后面我会通过实例来详细展开。
二、动机
前面介绍了数据模型的定义,那和前端开发又有什么关系呢?前端又不需要和数据库打交道,前端开发主要就是拿到数据显示就完了,那为什么需要数据模型呢?它是怎么助力前端开发的呢?我们先来看一下以下几个场景。
场景一
我们在前端开发中,通过ajax请求拿到服务端数据,然后将数据显示在视图上,经常会写如下代码:
如示例,假如我们要显示用户头像,通过取到headUrl的值绑定在src属性上即可。因为是异步加载获取的数据,在最终获取到headUrl的值之前,我们需要先判断cardData.buyerExperienceInfo的存在性,然后才能取值,否则在视图初次渲染之前会报如下错误:
在这种场景下,我们在开发中就不得不写一些防御性的代码,久而久之,项目中类似代码会越来越多,碰到层级深的,防御性代码就会写的越来越恶心。另外还有的就是,如果服务端在这中间某个字段删掉了,那就又得特殊处理了,否则会有一些未知的非空错误报错,这种编码方式会导致前端严重依赖服务端定义的数据结构,非常不利于后期维护。
场景二
平时开发中,我们拿到了服务端返回的数据,有些不是标准格式的,是无法直接在视图上直接使用的,是需要而外格式化处理的,比如我司服务端返回的的价格字段单位统一是分,跟时间相关的字段统一是毫秒值,这个时候我们在组件的生命周期内,就不得不而外增加一些对数据处理的逻辑,还有就是这部分处理在很多组件都是公用的,我们就不得不频繁编写类似的代码,数据处理逻辑没有得到复用。
场景三
在用户做了一些交互后,需要将一些数据存储到服务端,这个时候我们拿到的数据往往也是非标准的,就比如你要提交个表单,其中有个价格字段,你拿到价格单位可能是百位的,而服务端需要的单位必须是分位的,这个时候在提交数据之前,你又得对这部分数据进行处理,还有就是有些接口的参数是json字符串形式的,可能是多级嵌套的,你还要需要特意构造这样的参数数据格式,导致开发中编写了太多与业务无关的逻辑,随着项目逐渐扩大或者维护人员更迭,项目会越来越不好维护。
三、数据模型
在碰到这么多痛点之后,我就在想如何解决,回顾以上场景,总结下来存在以下几个问题:
前后端数据结构没有解耦,前端在应对不定的服务端数据结构前提下,需要编写过多的保护性代码,不利于维护的同时,代码健壮性也不高。
基础数据逻辑处理没有和UI视图解耦,容易阻塞视图渲染,同时,在视图组件上存在太多的基础数据逻辑处理,没有有效复用。
所以,这里我引入了数据模型的概念,那通过数据模型如何解决这类问题呢?下面我将通过两个实际案例来进一步呈现上述场景,以及引入了数据模型之后是如何解决的。
四、案列功能
这个案例使用Vue开发,功能很简单,就是通过ajax请求从服务端拿到数据,然后通过vue视图进行展现,效果如下:
五、常规实现
代码只展示主要功能代码,非完整实现
1.请求数据
在created生命周期内,向服务端请求数据。
2.数据处理
获取到数据之后,因为拿到的数据和最终UI上显示的格式不一致,需要转化一下数据格式。
3.渲染数据
给当前Vue实例赋值,然后在template里通过模板语法进行渲染
六、通过数据模型方式处理
1.定义数据模型
首先,我们可以专门建一个名叫model的文件夹,专门用来存放模型,然后定义卡片模型cardModel,其中数据定义格式如下:
type 必填,用来描述该字段的类型,支持String、Number、Date等类型
property 必填,数据路径,对应服务端数据结构的取值路径
value 选填,数据默认值,可不填
通过new Model()进行初始化,后续只需要通过model.parse(data)或者model.traverse(data)这个两个方法就可以完成正向映射和反向映射的过程。
具体的使用方式可以查看API
2.请求数据
通过axios请求接口,在拿到数据之后,调用parse方法解析数据,在解析的过程中会去做赋值操作以及数据格式化。
3.数据渲染
拿到数据,赋值给vue组件实例后,在template模板里面直接使用我们事先定义好的数据字段,不需要再去写类似a&a.b&a.b.c这样的代码,且不管服务端数据字段如何变化,视图渲染都不受影响,从而实现和服务端数据结构进行解耦。
与此同时,针对类似价格、时间等需要格式化的数据,我们可以直接使用,不需要再去写对应的格式化处理逻辑,从而专注于视图组件渲染处理。
通过引入数据模型,我们可以看到在模板里面引入变量的时候不需要进行各种判断,写法非常优雅,而且健壮性很强,即使服务端某个字段没有返回,我们这里也不会因此存在报错的可能性。且在脚本里面没有了数据格式化处理代码,从而不会因为数据处理逻辑代码可能存在的错误,打断UI的渲染。从而带来的更大好处是,随着项目的不断迭代,数据和视图有着清晰的划分,前端和后端进行了解耦,项目的可维护性得到保证。
4.反向映射
在库里面,还提供了traverse方法,和parse方法类似,区别是traverse是反向数据生成以及格式还原。
七、模型库的原理
最后,我来讲讲这个数据模型库(ducker-model)的实现原理,源码总共不到200行,还是简单的,可以通过这里下载查看,主要实现逻辑如下:
声明一个名叫Model的类。
通过new Model(options),传入模型结构,初始化数据模型属性,对外主要使用的是parse和traverse方法,
parse方法的实现过程就是遍历模型数据结构,拿到每个属性的数据路径,然后根据这个路径去取传入的的数据里面的数据,最后给事先定义好的属性赋值,在赋值的过程中,可以根据type格式化一些类似时间、价格类型的数据。
traverse方法刚好和parse相反,同样是遍历数据模型结构,拿到每个属性的数据路径,然后根据这个数据路径去设置一个新对象的值,这期间,反向格式化数据类型,最后返回这个新对象。
八、更进一步
目前这个库还很基础,只支持了一些常规的功能,能做的事情还很多,比如:
目前每次拿到请求一次数据之后都需要解析一次,那是否有个缓存机制,在数据没有变动的时候,直接从缓存取数据呢,或者可以直接watch这个解析之后的数据,做到数据变动,视图变动呢?
现有支持的类型还不够多,可以根据具体业务情况增加一些类型,以应对更多场景,提供可扩展的机制。
插件机制,比如表单处理,我们是否可以在数据模型定义的时候就定义好字段格式,在提交的时候就可以直接进行格式检测,抛出提醒呢?
目前的操作方式还比较适合纯粹的渲染式组件,如何和复杂的携带业务交互的组件融合也是需要考虑的。
… …
最后
案例
ducker-model-demo:https://github.com/simplefeel/ducker-model-demo
模型库
ducker-model:https://github.com/simplefeel/ducker-model
为你推荐
【第1686期】通过阅读源码提高你的 JavaScript 水平
福利时间
由@图灵出版社赞助5种共10本书,参与方式简单,只要在公众号后台回复 抽奖 即可参与,抽完即止。当然除了书之外,还有部分优惠券。
如有中奖的童鞋,麻烦添加下@情封微信:zhgb_f2er 领取奖品